package com.authine.cloudpivot.ext.applicationservice;

import cn.hutool.core.map.MapBuilder;
import com.authine.cloudpivot.ext.constants.ModelConst;
import com.authine.cloudpivot.ext.dto.model.invoice.InvoiceApply;
import com.authine.cloudpivot.ext.dto.model.invoice.InvoiceRecord;
import com.authine.cloudpivot.ext.utils.BoServiceUtils;
import com.authine.cloudpivot.ext.utils.JdbcTemplateUtils;
import com.authine.hermes.app.launcher.service.ApplicationService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StopWatch;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
public class InvoiceRecordService extends ApplicationService {


    /**
     * 保存发票申请单记录表返回确认开票需要的参数
     */
    public InvoiceRecord record(String invoiceId, List<InvoiceRecord> records) {

        Assert.notNull(invoiceId, "参数不能为空");
        Assert.isTrue(!CollectionUtils.isEmpty(records), "开票信息不能为空");

        InvoiceApply invoice = JdbcTemplateUtils.builder(ModelConst.T_INVOICE_APPLY).selectField(" * ")
                .eq("id", invoiceId)
                .queryForPOJO(InvoiceApply.class);
        Assert.notNull(invoice, "未查到对应的发票单");


        List<String> noDelRecordIds = new ArrayList<>();
        List<InvoiceRecord> saveRecords = new ArrayList<>();
        for (InvoiceRecord record : records) {

            Assert.isTrue(StringUtils.isNotBlank(record.getCode()), "发票代码不能为空");
            Assert.isTrue(StringUtils.isNotBlank(record.getNumber()), "发票号码不能为空");
            Assert.notNull(record.getPretax_amount(), "发票未税不能为空");
            Assert.notNull(record.getTax_payable(), "发票税额不能为空");

            if (null == record.getId()) {
                saveRecords.add(record);
            } else if (null == record.getInvoiceRecordType() || "update".equals(record.getInvoiceRecordType())) {
                update(record);
                noDelRecordIds.add(record.getId());
            }
        }

        //先删除在保存
        delete(invoiceId, noDelRecordIds);
        save(invoiceId, saveRecords);

        BigDecimal pretaxAmount = BigDecimal.ZERO, taxPayable = BigDecimal.ZERO;
        Set<String> numberSet = new HashSet<>(), codeSet = new HashSet<>();
        int numberAttachments = 0;

        List<InvoiceRecord> invoiceRecordList = JdbcTemplateUtils.builder(ModelConst.T_INVOICE_RECORD)
                .selectField(" * ").eq("invoice_apply_id", invoiceId)
                .queryForPOJOList(InvoiceRecord.class);;
        for (InvoiceRecord record : invoiceRecordList) {
            pretaxAmount = pretaxAmount.add(record.getPretax_amount());
            taxPayable = taxPayable.add(record.getTax_payable());
            numberSet.add(record.getNumber());
            codeSet.add(record.getCode());
            numberAttachments = numberAttachments + (record.getNumber_attachments() == null ? 0 : record.getNumber_attachments());
        }

        //开票未税+税额必须等于发票总额
        BigDecimal makeTotal = pretaxAmount.add( taxPayable);
        Assert.isTrue(makeTotal.compareTo(invoice.getTotal()) == 0, "发票未税(" + pretaxAmount
                + ")+税额(" + taxPayable + ")不等于发票总额(" + invoice.getTotal() + ")");

        String number = StringUtils.join(numberSet, ","), code = StringUtils.join(codeSet, ",");
        InvoiceRecord invoiceRecord = InvoiceRecord.builder().number(number).code(code).pretax_amount(pretaxAmount)
                .tax_payable(taxPayable).number_attachments(numberAttachments).build();

        return invoiceRecord;

    }

    public void save(String invoiceId, List<InvoiceRecord> saveRecords) {
        if (CollectionUtils.isEmpty(saveRecords)) {
            return;
        }
        List<Map<String, Object>> list = new ArrayList<>();
        MapBuilder mapBuilder = new MapBuilder(new HashMap<String, Object>());
        for (InvoiceRecord record : saveRecords) {
            mapBuilder.map().clear();
            mapBuilder.put("invoice_apply_id", invoiceId)
            .put("number", record.getNumber())
            .put("code", record.getCode())
            .put("pretax_amount", record.getPretax_amount())
            .put("tax_payable", record.getTax_payable())
            .put("number_attachments", record.getNumber_attachments());
            list.add(mapBuilder.build());
        }
        BoServiceUtils.createBo(ModelConst.T_INVOICE_RECORD, list);

    }

    /**
     * 删除开票申请单的record记录
     * @param invoiceId 开票申请单ID
     * @param noDelInvoiceRecordIds 不需要删除的record记录ID
     */
    public void delete(String invoiceId, List<String> noDelInvoiceRecordIds){
        List<String> deleteRecordIds = JdbcTemplateUtils.builder(ModelConst.T_INVOICE_RECORD)
                .selectField(" id ").eq("invoice_apply_id", invoiceId)
                .queryForList(String.class);
        if (CollectionUtils.isEmpty(deleteRecordIds)) {
            return;
        }

        if (!CollectionUtils.isEmpty(noDelInvoiceRecordIds)) {
            deleteRecordIds = deleteRecordIds.stream().filter(t -> !noDelInvoiceRecordIds.contains(t)).collect(Collectors.toList());
            if (CollectionUtils.isEmpty(deleteRecordIds)) {
                return;
            }
        }

        MapBuilder mapBuilder = new MapBuilder(new HashMap<String, Object>());
        for (String deleteRecordId : deleteRecordIds) {
            BoServiceUtils.deleteBo( ModelConst.T_INVOICE_RECORD, deleteRecordId, true);

        }
    }

    /**
     *
     * @param invoiceRecord
     */
    public  void update(InvoiceRecord invoiceRecord){
        InvoiceRecord record = JdbcTemplateUtils.builder(ModelConst.T_INVOICE_RECORD).selectField(" id ").eq("id", invoiceRecord.getId())
                .queryForPOJO(InvoiceRecord.class);
        if(record == null){
            return;
        }
        MapBuilder mapBuilder = new MapBuilder(new HashMap<String, Object>())
                .put("code", record.getCode())
                .put("protax_amount", record.getPretax_amount())
                .put("tax_payable", record.getTax_payable())
                .put("number", record.getNumber());
        BoServiceUtils.updateMainBo( ModelConst.T_INVOICE_RECORD, mapBuilder.build());
    }
}
